package com.aloda.scoring.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.aloda.ai.AiPlatformTypeExecutor;
import com.aloda.ai.impl.ZhiPuAiPlatform;
import com.aloda.constant.AiConstant;
import com.aloda.constant.ErrorCode;
import com.aloda.constant.ExceptionConstant;
import com.aloda.context.UserBaseContext;
import com.aloda.dto.AiGenerateResultDTO;
import com.aloda.dto.AiMessageDTO;
import com.aloda.dto.QuestionAndResultListDTO;
import com.aloda.dto.ScoreAndScoringResultDTO;
import com.aloda.dto.question.AiQuestionScoreDTO;
import com.aloda.dto.question.QuestionContentDTO;
import com.aloda.dto.scoringResult.AiScoreResult;
import com.aloda.dto.scoringResult.AiScoreScoringDTO;
import com.aloda.entity.*;
import com.aloda.enums.AiPlatformEnum;
import com.aloda.exception.BaseException;
import com.aloda.mapper.UserTokenMapper;
import com.aloda.scoring.DataTreating;
import com.aloda.scoring.ScoringStrategy;
import com.aloda.scoring.anno.ScoringStrategyConfig;
import com.aloda.utils.MyJsonUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 *  AI得分类应用评分策略
 */
@Slf4j
@ScoringStrategyConfig(appType = 0, scoringStrategy = 1)
public class AiScoreScoringStrategy implements ScoringStrategy {

    @Resource
    private DataTreating dataTreating;

    @Resource
    private UserTokenMapper userTokenMapper;

    @Resource
    private AiPlatformTypeExecutor aiPlatformTypeExecutor;

    @Resource
    private RedissonClient redissonClient;

    /**
     * AI评分评分类应用
     *
     * @param choices 选项集合
     * @param app     应用
     * @return 用户回答记录
     */
    @Override
    public UserAnswer doScore(List<String> choices, App app) {
        Long userId = UserBaseContext.getUser().getId();
        String lockKey = "user:" +  userId.toString() + ":answer-lock";
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁
            if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
                // 1.获取题目和评分结果列表
                QuestionAndResultListDTO questionAndResult = dataTreating.getQuestionAndResult(choices, app);
                Question question = questionAndResult.getQuestion();
                List<ScoringResult> scoringResultList = questionAndResult.getScoringResultList();

                // 2.获取对应的评分结果
                ScoreAndScoringResultDTO userScoreRange = dataTreating.getUserScoreRange(question, choices, scoringResultList);
                Integer scoreSum = userScoreRange.getResultScore();
                ScoringResult result = userScoreRange.getScoringResult();

                // 3.取出用户所有题目与选项集合
                List<QuestionContentDTO> questionContentDTOS = JSONUtil.toList(question.getQuestionContent(), QuestionContentDTO.class);
                ArrayList<AiQuestionScoreDTO> aiQuestionScoreDTOS = new ArrayList<>();
                for (int i = 0; i < questionContentDTOS.size(); i++) {
                    AiQuestionScoreDTO aiQuestionScoreDTO = new AiQuestionScoreDTO();
                    QuestionContentDTO questionContentDTO = questionContentDTOS.get(i);
                    aiQuestionScoreDTO.setTitle(questionContentDTO.getTitle());
                    int flag = i;
                    List<QuestionContentDTO.Option> options = questionContentDTO.getOptions()
                            .stream()
                            .filter(option -> choices.get(flag).equals(option.getKey()))
                            .toList();
                    aiQuestionScoreDTO.setValue(options.get(0).getValue());
                    aiQuestionScoreDTO.setScore(options.get(0).getScore());
                    aiQuestionScoreDTOS.add(aiQuestionScoreDTO);
                }

                // 4.封装消息
                AiScoreScoringDTO aiScoreScoringDTO = BeanUtil.copyProperties(result, AiScoreScoringDTO.class);
                String aiScoreScoringUserMessage = getAiScoreScoringUserMessage(app,
                        scoreSum,
                        aiQuestionScoreDTOS,
                        aiScoreScoringDTO);
                // 4.1.查看用户tokens是否满足本次调用
                float needTokens = aiScoreScoringUserMessage.length() / AiConstant.TOKEN_CONVERSION_RATIO;
                LambdaQueryWrapper<UserToken> userTokenLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userTokenLambdaQueryWrapper.eq(UserToken::getUserId, userId);
                UserToken userToken = userTokenMapper.selectOne(userTokenLambdaQueryWrapper);
                if (userToken == null || userToken.getTokenNum() < needTokens) {
                    throw new BaseException(ExceptionConstant.USER_TOKEN_NOT_ENOUGH);
                }
                log.info("用户{}调用AI对评分类应用判题，预计token:{}", userId, needTokens);

                // 5.调用AI判题

                // 创建AI对话数据传输对象
                AiMessageDTO aiMessageDTO = new AiMessageDTO();
                aiMessageDTO.setSystemMessage(AiConstant.AI_SCORE_SCORING_SYSTEM_MESSAGE);
                aiMessageDTO.setUserMessage(aiScoreScoringUserMessage);
                // 评分策略大模型固定使用智谱平台 GLM-4
                aiMessageDTO.setAiPlatform(AiPlatformEnum.ZHI_PU);
                aiMessageDTO.setModel(ZhiPuAiPlatform.ZhiPuModelEnum.ModelChatGLM4.getValue());
                aiMessageDTO.setTemperature(AiConstant.DEFAULT_TEMPERATURE);


                AiGenerateResultDTO aiGenerateResultDTO = null;
                try {
                    aiGenerateResultDTO = aiPlatformTypeExecutor.doSyncRequest(aiMessageDTO);
                } catch (Exception e) {
                    log.info("调用AI失败", e);
                    throw new BaseException(e.getMessage());
                }
                // 6.获取返回结果
                String aiGenerateResultDTOResult = aiGenerateResultDTO.getResult();
                log.info("用户{}调用AI对评分类应用判题结果：{}", userId, aiGenerateResultDTOResult);
                // 截取需要的 JSON 信息
                AiScoreResult aiScoreResult;
                try {
                    String jsonString = MyJsonUtils.cleanJsonString(aiGenerateResultDTOResult);
                    aiScoreResult = JSONUtil.toList(jsonString, AiScoreResult.class).get(0);
                } catch (Exception e) {
                    log.info("答案解析错误：", e);
                    throw new BaseException(ExceptionConstant.AI_GENERATE_ERROR);
                }

                // 7.扣除用户tokens
                // 8.通过返回结果扣除token,如果小于0,直接计为0
                userToken.setTokenNum(userToken.getTokenNum() - aiGenerateResultDTO.getTokenNum());
                if (userToken.getTokenNum() < 0) {
                    userToken.setTokenNum(0L);
                }
                userTokenMapper.updateById(userToken);
                // 9.封装UserAnswer
                // 10.构造返回值，填充答案对象的属性
                UserAnswer userAnswer = new UserAnswer();
                userAnswer.setAppId(app.getId());
                userAnswer.setAppType(app.getAppType());
                userAnswer.setScoringStrategy(app.getScoringStrategy());
                userAnswer.setChoices(JSONUtil.toJsonStr(choices));
                userAnswer.setResultId(result.getId());
                userAnswer.setResultName(aiScoreResult.getResultName());
                userAnswer.setResultDesc(aiScoreResult.getResultDesc());
                userAnswer.setResultPicture(result.getResultPicture());
                userAnswer.setResultScore(scoreSum);
                return userAnswer;
            } else {
                throw new BaseException(ExceptionConstant.SYSTEM_BUSY);
            }
        }catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BaseException(ErrorCode.SYSTEM_ERROR);
        } finally {
            if (lock != null && lock.isLocked()) {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }

    /**
     * 评分应用AI判题用户消息封装
     * @param app 应用
     * @param score 用户得分
     * @param questionList 题目列表
     * @param aiScoreScoringDTO 评分dto
     * @return 用户消息
     */
    private String getAiScoreScoringUserMessage(App app, int score, List<AiQuestionScoreDTO> questionList, AiScoreScoringDTO aiScoreScoringDTO) {
        StringBuilder userMessage = new StringBuilder();
        userMessage.append(app.getAppName()).append("\n");
        userMessage.append(app.getAppDesc()).append("\n");
        userMessage.append(score).append("\n");
        String jsonStr = JSONUtil.toJsonStr(questionList);
        userMessage.append(jsonStr).append("\n");
        userMessage.append(JSONUtil.toJsonStr(aiScoreScoringDTO));
        return userMessage.toString();
    }
}
